package com.flowable.controller;


import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.common.annotation.Log;
import com.common.core.controller.BaseController;
import com.common.core.domain.AjaxResult;
import com.common.core.domain.entity.SysDept;
import com.common.core.domain.entity.SysUser;
import com.common.enums.BusinessType;
import com.common.utils.SecurityUtils;
import com.common.utils.StringUtils;
import com.flowable.common.NumberUtils;
import com.flowable.common.PageResult;
import com.flowable.controller.oa.vo.AdminUserRespDTO;
import com.flowable.controller.oa.vo.DeptRespDTO;
import com.flowable.convert.task.BpmProcessInstanceConvert;
import com.flowable.domain.dto.BpmProcessInstanceCreateReqDTO;
import com.flowable.domain.instance.BpmApprovalDetailReqVO;
import com.flowable.domain.instance.BpmProcessInstanceCancelReqVO;
import com.flowable.domain.instance.BpmProcessInstancePageReqVO;
import com.flowable.domain.instance.BpmProcessInstanceRespVO;
import com.flowable.domain.vo.FlowTaskVo;
import com.flowable.service.IFlowDefinitionService;
import com.flowable.service.IFlowInstanceService;
import com.flowable.service.IFlowTaskService;
import com.system.service.ISysDeptService;
import com.system.service.ISysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;
import java.util.Map;

import static com.common.utils.CollectionUtils.convertList;
import static com.common.utils.CollectionUtils.convertSet;

/**
 * <p>工作流流程实例管理<p>
 *
 * @author Tony
 * @date 2021-04-03
 */
@Slf4j
@Api(tags = "工作流流程实例管理")
@RestController
@RequestMapping("/flowable/instance")
public class FlowInstanceController extends BaseController {

    @Autowired
    private IFlowInstanceService flowInstanceService;

    @Autowired
    private IFlowTaskService flowTaskService;

    @Autowired
    private ISysUserService userService;
    @Autowired
    private ISysDeptService deptService;

    @Autowired
    private IFlowDefinitionService flowDefinitionService;

    @ApiOperation(value = "根据流程定义id启动流程实例")
    @PostMapping("/startBy/{procDefId}")
    public AjaxResult startById(@ApiParam(value = "流程定义id") @PathVariable(value = "procDefId") String procDefId,
                                @ApiParam(value = "变量集合,json对象") @RequestBody Map<String, Object> variables) {
        return flowInstanceService.startProcessInstanceById(procDefId, variables);

    }

    @GetMapping("/manager-page")
    @Operation(summary = "获得管理流程实例的分页列表", description = "在【流程实例】菜单中，进行调用")
    public AjaxResult getProcessInstanceManagerPage(
            @Valid BpmProcessInstancePageReqVO pageReqVO) {
        PageResult<HistoricProcessInstance> pageResult = flowInstanceService.getProcessInstancePage(
                null, pageReqVO);
        if (CollUtil.isEmpty(pageResult.getList())) {
            return success(PageResult.empty(pageResult.getTotal()));
        }

        // 拼接返回
        Map<String, List<Task>> taskMap = flowTaskService.getTaskMapByProcessInstanceIds(
                convertList(pageResult.getList(), HistoricProcessInstance::getId));
        Map<String, ProcessDefinition> processDefinitionMap = flowDefinitionService.getProcessDefinitionMap(
                convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId));
//        Map<String, BpmCategoryDO> categoryMap = categoryService.getCategoryMap(
//                convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory));
        // 发起人信息
        Map<Long, SysUser> userMap = userService.getUserMap(
                convertSet(pageResult.getList(),
                        processInstance -> NumberUtils.parseLong(processInstance.getStartUserId())));
        Map<Long, SysDept> deptMap = deptService.getDeptMap(
                convertSet(userMap.values(), SysUser::getDeptId));
        return success(BpmProcessInstanceConvert.INSTANCE.buildProcessInstancePage(pageResult,
                processDefinitionMap, taskMap, userMap, deptMap));
    }

    @ApiOperation(value = "激活或挂起流程实例")
    @PostMapping(value = "/updateState")
    public AjaxResult updateState(@ApiParam(value = "1:激活,2:挂起", required = true) @RequestParam Integer state,
                                  @ApiParam(value = "流程实例ID", required = true) @RequestParam String instanceId) {
        flowInstanceService.updateState(state,instanceId);
        return AjaxResult.success();
    }

    @ApiOperation("结束流程实例")
    @PostMapping(value = "/stopProcessInstance")
    public AjaxResult stopProcessInstance(@RequestBody FlowTaskVo flowTaskVo) {
        flowInstanceService.stopProcessInstance(flowTaskVo);
        return AjaxResult.success();
    }

    @ApiOperation(value = "删除流程实例")
    @Log(title = "删除任务", businessType = BusinessType.DELETE)
    @DeleteMapping(value = "/delete/{instanceIds}")
    public AjaxResult delete(@ApiParam(value = "流程实例ID", required = true) @PathVariable String[] instanceIds,
                             @ApiParam(value = "删除原因") @RequestParam(required = false) String deleteReason) {
        for (String instanceId : instanceIds) {
            flowInstanceService.delete(instanceId,deleteReason);
        }
        return AjaxResult.success();
    }
    @ApiOperation(value = "启动流程实例")
    @GetMapping("/createProcessInstance")
    public String createProcessInstance(@RequestParam(value = "userId")String userId, @RequestParam(value = "businessId")String businessId,@RequestParam(value = "tablename")String tablename,@RequestParam(value = "processDefinitionKey")String processDefinitionKey){
        try {
            if (StringUtils.isEmpty(businessId) || StringUtils.isEmpty(tablename)||StringUtils.isEmpty(processDefinitionKey))
                return "参数不全";
            BpmProcessInstanceCreateReqDTO bpmPI = new BpmProcessInstanceCreateReqDTO();
            bpmPI.setBusinessKey(businessId);
            bpmPI.setProcessDefinitionKey(processDefinitionKey);
            bpmPI.setTableName(tablename);

            String processInstanceId = flowInstanceService.createProcessInstance(Long.parseLong(userId), bpmPI);
            return processInstanceId;
        }catch (Exception e){
            return  e.toString();
        }


    }
    @ApiOperation(value = "获得审批详情")
    @GetMapping("/get-approval-detail")
    @Operation(summary = "获得审批详情")
    @Parameter(name = "id", description = "流程实例的编号", required = true)
    public AjaxResult  getApprovalDetail(@Valid BpmApprovalDetailReqVO reqVO) {
        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
        return success(flowInstanceService.getApprovalDetail(sysUser.getUserId(), reqVO));
    }

    @ApiOperation(value = "获取流程实例的 BPMN 模型视图 在【流程详细】界面中，进行调用")
    @GetMapping("/get-bpmn-model-view")
    @Operation(summary = "获取流程实例的 BPMN 模型视图", description = "在【流程详细】界面中，进行调用")
    @Parameter(name = "id", description = "流程实例的编号", required = true)
    public AjaxResult getProcessInstanceBpmnModelView(@RequestParam(value = "id") String id) {
        return success(flowInstanceService.getProcessInstanceBpmnModelView(id));
    }
    @ApiOperation(value = "用户取消流程实例")
    @DeleteMapping("/cancel-by-start-user")
    @Operation(summary = "用户取消流程实例", description = "取消发起的流程")
    public AjaxResult cancelProcessInstanceByStartUser(
            @Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) {
        System.out.println("撤销执行开始");
        long startTime = System.currentTimeMillis();
        //flowInstanceService.cancelProcessInstanceByStartUser(SecurityUtils.getLoginUser().getUserId(),cancelReqVO);
        flowInstanceService.cancelProcessInstanceByStartUserForce(SecurityUtils.getLoginUser().getUserId(),cancelReqVO);
        long endTime = System.currentTimeMillis();
        long executionTime = endTime - startTime;
        System.out.println("撤销执行时间为：" + executionTime + "毫秒");

        return success(true);
    }

    @ApiOperation(value = "用户取消流程实例,删除流程实例版")
    @DeleteMapping("/cancel-by-start-user-v1")
    @Operation(summary = "用户取消流程实例", description = "取消发起的流程")
    public AjaxResult cancelProcessInstanceByStartUserForce(
            @Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) {
        flowInstanceService.cancelProcessInstanceByStartUserForce(SecurityUtils.getLoginUser().getUserId(), cancelReqVO);
        return success(true);
    }
    @ApiOperation(value = "管理员取消流程实例")
    @DeleteMapping("/cancel-by-admin")
    @Operation(summary = "管理员取消流程实例", description = "管理员撤回流程")

    public AjaxResult cancelProcessInstanceByManager(
            @Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) {
        flowInstanceService.cancelProcessInstanceByAdmin(SecurityUtils.getLoginUser().getUserId(), cancelReqVO);
        return success(true);
    }

    @ApiOperation(value = "根据流程key,删除此key所有实例")
    @DeleteMapping(value = "/deletebykey/{processkey}")
    @Operation(summary = "管理员取消流程实例", description = "管理员撤回流程")
    public AjaxResult deletebyKey(@ApiParam(value = "流程定义key", required = true) @PathVariable String processkey) {
        flowInstanceService.deletebyKey(processkey);
        return AjaxResult.success();
    }


}
